package com.zzyl.job;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import com.github.pagehelper.Page;
import com.zzyl.constant.CacheConstants;
import com.zzyl.entity.AlertData;
import com.zzyl.entity.AlertRule;
import com.zzyl.entity.DeviceData;
import com.zzyl.mapper.AlertDataMapper;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.service.FloorService;
import com.zzyl.service.impl.FloorServiceImpl;
import com.zzyl.vo.*;
import io.swagger.models.auth.In;
import jodd.bean.BeanException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.encrypt.AesBytesEncryptor;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class MyTask {
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private AlertDataMapper alertDataMapper;
    /**
     * 定时任务入口，按业务流程依次处理报警规则和设备数据
     */
    @Scheduled(cron = "0/5 * * * * ? ")
    public void task() {
        // 1. 获取告警规则
        List<AlertRule> alertRulesList = getAlertRules();
        if (ObjectUtil.isEmpty(alertRulesList)) {
            return;
        }

        // 2. 获取设备数据
        Map<String, List<DeviceData>> deviceDataMap = getDeviceDataFromRedis();
        if (ObjectUtil.isEmpty(deviceDataMap)) {
            return;
        }

        // 3. 过滤最近1分钟内的设备数据
        Map<String, List<DeviceData>> filteringDeviceDataMap = filterRecentDeviceData(deviceDataMap);
        if (ObjectUtil.isEmpty(filteringDeviceDataMap)) {
            return;
        }

        // 4. 按设备ID分类告警规则
        Map<String, List<AlertRule>> alertRulesMap = groupAlertRulesByDevice(alertRulesList);
        if (ObjectUtil.isEmpty(alertRulesMap)) {
            return;
        }

        // 5. 过滤在生效时间范围内的规则
        Map<String, List<AlertRule>> filteringAlertRulesMap = filterActiveAlertRules(alertRulesMap);
        if (ObjectUtil.isEmpty(filteringAlertRulesMap)) {
            return;
        }

        // 6. 处理告警规则
        processAlertRules(filteringAlertRulesMap, filteringDeviceDataMap);
    }
    private void sendAndSaveAlertData(AlertRule filteringAlertRules, DeviceData filteringDeviceData) {
        // 循环filteringDeviceDataMap
        //  判断是 0：随身设备 1：固定设备
        if (filteringDeviceData.getLocationType() == 1) {
            List<Long> longs = deviceMapper.selectNursingIdsByIotIdWithBed(filteringDeviceData.getIotId());
            AlertData result = AlertData.builder()
                    .iotId(filteringDeviceData.getIotId())
                    .deviceName(filteringDeviceData.getDeviceName())
                    .nickname(filteringDeviceData.getNickname())
                    .productKey(filteringDeviceData.getProductKey())
                    .productName(filteringDeviceData.getProductName())
                    .functionId(filteringDeviceData.getIotId())
                    .accessLocation(filteringDeviceData.getAccessLocation())
                    .locationType(filteringDeviceData.getLocationType())
                    .physicalLocationType(filteringDeviceData.getPhysicalLocationType())
                    .deviceDescription(filteringDeviceData.getDeviceDescription())
                    .dataValue(filteringDeviceData.getDataValue())
                    .alertRuleId(filteringAlertRules.getId())
                    .alertReason(filteringAlertRules.getAlertRuleName())
                    .processingResult("")
                    .processorId(filteringAlertRules.getCreateBy())
                    .processorName(filteringAlertRules.getCreator())
                    .processingTime(LocalDateTime.now())
                    .type(filteringAlertRules.getAlertDataType())
                    .status(1)
                    .userId(longs.get(0)).build();
            List<AlertData> success = new ArrayList<>();
            success.add(result);
            alertDataMapper.batchInsert(success);
        } else if (filteringDeviceData.getLocationType() == 0) {
            List<Long> longs = deviceMapper.selectNursingIdsByIotIdWithBed(filteringDeviceData.getIotId());
            System.out.println(longs);
        }
    }
/**
 * 查询所有报警规则并转为POJO列表
 *
 * @return 报警规则列表
 */
private List<AlertRule> getAlertRules() {
    Page<AlertRuleVo> page = alertRuleMapper.page(null, null, null);
    List<AlertRuleVo> alertRuleVoList = page.getResult();
    List<AlertRule> alertRulesList = BeanUtil.copyToList(alertRuleVoList, AlertRule.class);

    alertRulesList.forEach(alertRuleVo -> {
        if (ObjectUtil.isEmpty(alertRuleVo)) {
            log.info("没有规则的数据");
        }
    });
    return alertRulesList;
}

/**
 * 从Redis获取所有设备的最新数据
 *
 * @return 设备数据Map，key为iotId
 */
private Map<String, List<DeviceData>> getDeviceDataFromRedis() {
    List<Object> values = redisTemplate.opsForHash().values(CacheConstants.DEVICE_LASTDATA_CACHE_KEY);
    if (ObjectUtil.isEmpty(values)) {
        return null;
    }

    Map<String, List<DeviceData>> deviceDataMap = new HashMap<>();
    for (int i = 0; i < values.size(); i++) {
        if (ObjectUtil.isEmpty(values)) {
            return null;
        }
        List<DeviceData> deviceData = JSONUtil.toList(values.get(i).toString(), DeviceData.class);
        deviceDataMap.put(deviceData.get(i).getIotId(), deviceData);
    }
    return deviceDataMap;
}

/**
 * 过滤出最近一分钟内上报的设备数据
 *
 * @param deviceDataMap 所有设备数据
 * @return 过滤后的设备数据Map
 */
private Map<String, List<DeviceData>> filterRecentDeviceData(Map<String, List<DeviceData>> deviceDataMap) {
    Map<String, List<DeviceData>> filteringDeviceDataMap = new HashMap<>();
    boolean flag = true;
    for (String iotId : deviceDataMap.keySet()) {
        flag = true;
        List<DeviceData> deviceDataList = deviceDataMap.get(iotId);
        for (DeviceData deviceData : deviceDataList) {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime dataTime = deviceData.getAlarmTime();
            Duration duration = Duration.between(dataTime, now);
            if (duration.toMinutes() > 1) {
                flag = false;
            }
            break;
        }
        if (flag) {
            filteringDeviceDataMap.put(iotId, deviceDataList);
        }
    }
    return filteringDeviceDataMap;
}

/**
 * 按设备ID分组报警规则
 *
 * @param alertRulesList 报警规则列表
 * @return 分组后的报警规则Map
 */
private Map<String, List<AlertRule>> groupAlertRulesByDevice(List<AlertRule> alertRulesList) {
    Map<String, List<AlertRule>> alertRulesMap = new HashMap<>();
    for (AlertRule alertRule : alertRulesList) {
        if (alertRulesMap.containsKey(alertRule.getIotId())) {
            alertRulesMap.get(alertRule.getIotId()).add(alertRule);
        } else {
            List<AlertRule> alertRuleList = new ArrayList<>();
            alertRuleList.add(alertRule);
            alertRulesMap.put(alertRule.getIotId(), alertRuleList);
        }
    }
    return alertRulesMap;
}

/**
 * 过滤出当前时间在生效时间范围内的报警规则
 *
 * @param alertRulesMap 分组后的报警规则Map
 * @return 过滤后的报警规则Map
 */
private Map<String, List<AlertRule>> filterActiveAlertRules(Map<String, List<AlertRule>> alertRulesMap) {
    Map<String, List<AlertRule>> filteringAlertRulesMap = new HashMap<>();
    Set<String> strings = alertRulesMap.keySet();
    for (String iotId : strings) {
        List<AlertRule> activeRules = new ArrayList<>();
        List<AlertRule> alertRules = alertRulesMap.get(iotId);
        for (AlertRule alertRule : alertRules) {
            String timeRange = alertRule.getAlertEffectivePeriod();
            LocalTime now = LocalTime.now();
            String[] timeRangeParts = timeRange.split("~");
            LocalTime startTime = LocalTime.parse(timeRangeParts[0]);
            LocalTime endTime = LocalTime.parse(timeRangeParts[1]);
            if (!now.isBefore(startTime) && !now.isAfter(endTime)) {
                activeRules.add(alertRule);
            }
        }
        if (!activeRules.isEmpty()) {
            filteringAlertRulesMap.put(iotId, activeRules);
        }
    }
    return filteringAlertRulesMap;
}

/**
 * 处理所有报警规则，判断是否触发报警并计数
 *
 * @param filteringAlertRulesMap 生效的报警规则
 * @param filteringDeviceDataMap 有效的设备数据
 */
private void processAlertRules(Map<String, List<AlertRule>> filteringAlertRulesMap,
                               Map<String, List<DeviceData>> filteringDeviceDataMap) {
    for (String iotId : filteringAlertRulesMap.keySet()) {
        List<AlertRule> alertRules = filteringAlertRulesMap.get(iotId);
        for (AlertRule alertRule : alertRules) {
            if (iotId.equals("-1")) {
                processGlobalAlertRule(alertRule, filteringDeviceDataMap);
            } else {
                processDeviceAlertRule(alertRule, iotId, filteringDeviceDataMap);
            }
        }
    }

}

/**
 * 处理全局报警规则（iotId为-1），遍历所有设备数据
 *
 * @param alertRule              全局报警规则
 * @param filteringDeviceDataMap 有效的设备数据
 */
private void processGlobalAlertRule(AlertRule alertRule, Map<String, List<DeviceData>> filteringDeviceDataMap) {
    for (int i = 0; i < filteringDeviceDataMap.size(); i++) {
        Set<String> filteringDeviceDataMapKey = filteringDeviceDataMap.keySet();
        for (String iotId1 : filteringDeviceDataMapKey) {
            List<DeviceData> deviceDataList = filteringDeviceDataMap.get(iotId1);
            for (DeviceData deviceData : deviceDataList) {
                if (deviceData.getFunctionId().equals(alertRule.getFunctionId())) {
                    processAlertCondition(deviceData, alertRule);
                }
            }
        }
    }
}

/**
 * 处理指定设备的报警规则
 *
 * @param alertRule              设备报警规则
 * @param iotId                  设备ID
 * @param filteringDeviceDataMap 有效的设备数据
 */
private void processDeviceAlertRule(AlertRule alertRule, String iotId,
                                    Map<String, List<DeviceData>> filteringDeviceDataMap) {
    List<DeviceData> deviceDataList = filteringDeviceDataMap.get(iotId);
    for (DeviceData deviceData : deviceDataList) {
        if (deviceData.getFunctionId().equals(alertRule.getFunctionId())) {
            processAlertCondition(deviceData, alertRule);
        }
    }
}

/**
 * 判断设备数据是否满足报警条件，满足则更新Redis计数
 *
 * @param deviceData 设备数据
 * @param alertRule  报警规则
 */
private void processAlertCondition(DeviceData deviceData, AlertRule alertRule) {
    int dataValue = Integer.parseInt(deviceData.getDataValue());
    String operator = alertRule.getOperator();
    int value = alertRule.getValue().intValue();

    String cacheKey = deviceData.getIotId() + ":" + alertRule.getAlertRuleName() + ":" + alertRule.getFunctionId();
    String countKey = deviceData.getIotId() + ":" + alertRule.getAlertRuleName() + ":" + alertRule.getFunctionId() + ":" + deviceData.getProductKey();
    String alertSilentPeriod = CacheConstants.ALERT_SILENT_PERIOD;

    if (operator.equals(">=")) {
        if (dataValue >= value) {
            Long s = redisTemplate.getExpire(alertSilentPeriod + countKey);
            if (s > 0) {
                return;
            }
            updateAlertCount(deviceData, cacheKey, alertRule);
        } else {
            clearAlertCount(cacheKey);
        }
    } else if (operator.equals("<")) {
        if (dataValue < value) {
            if (redisTemplate.opsForValue().get(alertSilentPeriod + countKey) != null) {
                return;
            }
            updateAlertCount(deviceData, cacheKey, alertRule);
        } else {
            clearAlertCount(cacheKey);
        }
    }
}
/**
 * 达到周期,删除Redis中的报警计数,报警
 *
 * @param cacheKey Redis的key
 */
private void updateAlertCount(DeviceData deviceData, String cacheKey, AlertRule alertRule) {
    String alertSilentPeriod = CacheConstants.ALERT_SILENT_PERIOD;
    String countKey = deviceData.getIotId() + ":" + alertRule.getAlertRuleName() + ":" + alertRule.getFunctionId() + ":" + deviceData.getProductKey();
    String key = CacheConstants.DEVICE_DATA_CACHE_KEY + ":" + cacheKey;
    String value = redisTemplate.opsForValue().get(key);
    if (value != null) {
        int count = Integer.parseInt(value);
        if (count >= alertRule.getDuration()) {
            clearAlertCount(cacheKey);
            redisTemplate.opsForValue().set(alertSilentPeriod + countKey, "沉默周期为:" + alertRule.getAlertSilentPeriod() + "分钟");
            // 给我加一个5分钟的过期时间
            redisTemplate.expire(alertSilentPeriod + countKey, alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);
            sendAndSaveAlertData(alertRule, deviceData);
        }
        redisTemplate.opsForValue().set(key, String.valueOf(Integer.parseInt(value) + 1));
    } else {
        redisTemplate.opsForValue().set(key, "1");
    }
}
/**
 * 没有达到阈值，则清空Redis中的计数
 *
 * @param cacheKey Redis的key
 */
private void clearAlertCount(String cacheKey) {
    String key = CacheConstants.DEVICE_DATA_CACHE_KEY + ":" + cacheKey;
    redisTemplate.delete(key);
}
}
